<?php

namespace app\components;

use Yii;

/**
 * Instagram filters with PHP and ImageMagick  
 *  
 * @package    Instagraph  
 * @author     Webarto <dejan.marjanovic@gmail.com>  
 * @copyright  NetTuts+  
 * @license    http://creativecommons.org/licenses/by-nc/3.0/ CC BY-NC  
 */
class Instagraph {

    public $_image = NULL;
    public $_output = NULL;
    public $_prefix = 'IMG';
    private $_width = NULL;
    private $_height = NULL;
    private $_tmp = NULL;
    public $isEcho=false;
    public static function factory($image, $output) {
        return new Instagraph($image, $output);
    }

    public function __construct($image, $output = NULL) {
        if (file_exists($image)) {
            $this->_image = $image;
            list($this->_width, $this->_height) = getimagesize($image);
            $this->_output = $output;
        } else {
            throw new \yii\base\Exception('File not found. Aborting.');
        }
    }

    public function tempfile() {
        # copy original file and assign temporary name  
        $rand = md5(rand(100, 999999) . time());
        $this->_tmp = Yii::$app->runtimePath . '/cache/' . $this->_prefix . $rand;
        copy($this->_image, $this->_tmp);
    }

    public function output() {
        # rename working temporary file to output filename  
        if ($this->_output) {
            rename($this->_tmp, $this->_output);
        }
        if ($this->isEcho) {
            header("Content-Type: image/{$this->getImageFormat()}");
            $content = file_get_contents($this->_tmp);
            unlink($this->_tmp);
            echo $content;
        }
    }

    public function execute($command) {
        # remove newlines and convert single quotes to double to prevent errors  
        $command = str_replace(array("\n", "'"), array('', '"'), $command);
        $command = escapeshellcmd($command);
        # execute convert program  
        exec($command);
    }

    /** ACTIONS */
    public function colortone($input, $color, $level, $type = 0) {
        $args[0] = $level;
        $args[1] = 100 - $level;
        $negate = $type == 0 ? '-negate' : '';

        $this->execute("convert  
        {$input}  
        ( -clone 0 -fill '$color' -colorize 100% )  
        ( -clone 0 -colorspace gray $negate )  
        -compose blend -define compose:args=$args[0],$args[1] -composite  
        {$input}");
    }

    public function border($input, $color = 'black', $width = 20) {
        $this->execute("convert $input -bordercolor $color -border {$width}x{$width} $input");
    }

    public function frame($input, $frame) {
        $this->execute("convert $input ( '$frame' -resize {$this->_width}x{$this->_height}! -unsharp 1.5×1.0+1.5+0.02 ) -flatten $input");
    }

    public function vignette($input, $color_1 = 'none', $color_2 = 'black', $crop_factor = 1.5) {
        $crop_x = floor($this->_width * $crop_factor);
        $crop_y = floor($this->_height * $crop_factor);

        $this->execute("convert  
        ( {$input} )  
        ( -size {$crop_x}x{$crop_y}  
        radial-gradient:$color_1-$color_2  
        -gravity center -crop {$this->_width}x{$this->_height}+0+0 +repage )  
        -compose multiply -flatten  
        {$input}");
    }

    private function getImageFormat() {
        return 'png';
    }

    /**
     * 输出
     */
    public function getImageBlob() {
        
    }

    /**
     *  滤镜生成一张黑白、有浅蓝底色的高对比度的图像。在现实生活中，这会用Holga相机和Ilford X2胶片来实现。
     * 文字解释：创建一个工作文件，将图像加载到内存，提高一点亮度和饱和度，改变剩下的颜色为深紫色，伽马校正，增加更多对比度，把所有改变保存到一个文件中。添加一个20像素的黑色边框。是不是很简单？
     */
    public function gotham() {
        $this->tempfile();
        $this->execute("convert $this->_tmp -modulate 120,10,100 -fill '#222b6d' -colorize 20 -gamma 0.5 -contrast -contrast $this->_tmp");
        $this->border($this->_tmp);
        $this->output();
    }

    /**
     * Toaster滤镜类似于老宝丽来相机的效果，它有以粉红色或橙色为发光中心的鲜艳颜色。按Instagram CEO的话来说，它是最难实现的效果之一。
     * 文字解释：创建一个工作文件，将图像加载到内存，将黑色变为暗红色，提高亮度，将饱和度设为1/5，执行伽玛校正（使图像更亮），添加更多对比度并保存。最后，添加一个灰色的晕影（边缘去掉一点饱和度）以及一个实现色彩燃烧效果的橙色翻转晕影。
     */
    public function toaster() {
        $this->tempfile();
        $this->colortone($this->_tmp, '#330000', 100, 0);
        $this->execute("convert $this->_tmp -modulate 150,80,100 -gamma 1.2 -contrast -contrast $this->_tmp");
        $this->vignette($this->_tmp, 'none', 'LavenderBlush3');
        $this->vignette($this->_tmp, '#ff9966', 'none');
        $this->output();
    }

    /**
     * Nashville有很棒的80年代时尚掉色照片似的感觉。它通过洋红和桃红色调产生图片。此外，它还添加一个相框来获得幻灯片的外观。这是最容易实现并且最流行的Instagram滤镜之一。
     * 文字解释：创建一个工作文件，将图像加载到内存，将黑色变成靛蓝色，将白色变成桃红色，增强对比度，将饱和度提高一半，进行伽马自动校正。从PNG文件添加相框。
     */
    public function nashville() {
        $this->tempfile();

        $this->colortone($this->_tmp, '#222b6d', 100, 0);
        $this->colortone($this->_tmp, '#f7daae', 100, 1);

        $this->execute("convert $this->_tmp -contrast -modulate 100,150,100 -auto-gamma $this->_tmp");
        $this->frame($this->_tmp, __FUNCTION__);

        $this->output();
    }

    /**
     *  Lomography就是通过相框和柔焦来创建高对比度的照片。在现实生活中，这种效果大多通过Holga，LOMO LC-A或者所谓的玩具相机（有塑料镜片的照相机）来实现。这种效果相当容易重现，我们将红色和绿色通道的对比度简单的提高1/3，并且添加一个相框。你可以随意进行实验。
     *    提示：如果你喜欢没有晕影的Lomo效果，只需要注释掉或者移除对应代码。文字解释：创建一个工作文件，将图像加载到内存，将红色通道的对比度提高1/3，再次将红色通道对比度提高1/3，应用一个晕影。
     */
    public function lomo() {
        $this->tempfile();

        $command = "convert {$this->_tmp} -channel R -level 33% -channel G -level 33% $this->_tmp";

        $this->execute($command);
        $this->vignette($this->_tmp);

        $this->output();
    }

    /**
     * 这种效果以达尔文命名，它使用了一个强力的桃色和橙色覆盖层，并且添加了一个掉色的相框。
     * 文字解释：创建一个工作文件，将图像加载到内存，规范化，提高1/5的亮度，提高饱和度的一半，创建一个桃色和橙色的覆盖层，并且应用多重混合模式。最后，使用PNG文件添加一个相框。
     */
    public function kelvin() {
        $this->tempfile();

        $this->execute("convert  
    ( $this->_tmp -auto-gamma -modulate 120,50,100 )  
    ( -size {$this->_width}x{$this->_height} -fill 'rgba(255,153,0,0.5)' -draw 'rectangle 0,0 {$this->_width},{$this->_height}' )  
    -compose multiply  
    $this->_tmp");
        $this->frame($this->_tmp, __FUNCTION__);

        $this->output();
    }

}
